import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from torch.utils.data import DataLoader, Subset

# 假设我们有一个数据集和模型
dataset = ...  # 数据集
model = ...  # 模型

# 划分训练集和验证集
train_indices, val_indices = train_test_split(range(len(dataset)), test_size=0.2, random_state=42)
train_subset = Subset(dataset, train_indices)
val_subset = Subset(dataset, val_indices)

train_loader = DataLoader(train_subset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_subset, batch_size=32, shuffle=False)

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

best_val_loss = float('inf')
best_model = None

# 超参数搜索范围
learning_rates = [0.001, 0.01, 0.1]
batch_sizes = [16, 32, 64]

for lr in learning_rates:
    for batch_size in batch_sizes:
        # 重新初始化模型和优化器
        model = ...  # 重新实例化模型
        optimizer = optim.Adam(model.parameters(), lr=lr)

        # 训练模型
        model.train()
        for epoch in range(num_epochs):
            for images, labels in train_loader:
                images, labels = images.to(device), labels.to(device)
                optimizer.zero_grad()
                outputs = model(images)
                loss = criterion(outputs, labels)
                loss.backward()
                optimizer.step()

        # 在验证集上评估模型
        model.eval()
        val_loss = 0.0
        with torch.no_grad():
            for images, labels in val_loader:
                images, labels = images.to(device), labels.to(device)
                outputs = model(images)
                loss = criterion(outputs, labels)
                val_loss += loss.item()

        val_loss /= len(val_loader)
        print(f'Learning Rate: {lr}, Batch Size: {batch_size}, Validation Loss: {val_loss}')

        # 更新最佳模型
        if val_loss < best_val_loss:
            best_val_loss = val_loss
            best_model = model

# 使用最佳模型进行后续任务
print(f'Best Validation Loss: {best_val_loss}')

# 在这个示例中，我们首先将数据集划分为训练集和验证集。然后，我们遍历不同的超参数组合（学习率和批大小），
# 在每个组合下训练模型并在验证集上评估其性能。
# 最后，我们选择在验证集上表现最好的模型作为最终模型。

# 验证集（Validation Set）在机器学习和深度学习中扮演着非常重要的角色，特别是在模型训练过程中。
# 这句话“验证集：用于调整模型的超参数和选择最佳模型”具体指的是以下两个方面：
#
# 1. 调整模型的超参数
# 超参数（Hyperparameters）是指那些在模型训练之前需要设置的参数，它们不能通过训练数据直接学习到。
# 常见的超参数包括学习率、批大小、正则化系数等。
#
# 为什么需要调整超参数？
# 提高模型性能：不同的超参数组合可能会显著影响模型的性能。通过调整超参数，可以找到最优的组合，从而提高模型的准确性和泛化能力。
# 防止过拟合：合适的超参数可以帮助防止模型过拟合训练数据，从而在测试数据上表现更好。
# 如何调整超参数？
# 网格搜索（Grid Search）：系统地遍历所有可能的超参数组合，评估每个组合在验证集上的表现，选择表现最好的组合。
# 随机搜索（Random Search）：随机采样超参数空间，而不是遍历所有可能的组合，通常比网格搜索更高效。
# 贝叶斯优化（Bayesian Optimization）：使用概率模型来选择下一个最有可能提高验证集性能的超参数组合。
# 2. 选择最佳模型
# 在训练多个模型或尝试不同的算法时，我们需要选择一个最佳的模型。验证集在这个过程中起到了关键作用。
#
# 如何选择最佳模型？
# 交叉验证（Cross-Validation）：将数据集划分为多个子集，轮流使用其中一个子集作为验证集，其余子集作为训练集。
# 这样可以更全面地评估模型的性能，减少对单一验证集结果的依赖。
# 验证集性能评估：在每个超参数组合下，训练模型并在验证集上评估其性能。选择在验证集上表现最好的模型作为最终模型。